Release v0.15.0 - xchain-encoder - #8
Merged
Merged
Conversation
Levelling develop with master, the ceremony step that closes a train. Commits that reach master without coming back leave the branch all work lands on missing what shipped, so the next diff off develop reads as though it never happened.
…s the caller's UTXO list verbatim
…s without silencing the 503
…s cannot respend a UTXO UTXO reservation was not synchronous with the build, so a chained send could be composed against an outpoint an earlier send had already claimed and broadcast the same transaction twice. Reservation no longer depends on the tracker fetch, and exact-input mode claims or refuses the named set outright rather than silently skipping a reserved outpoint.
One wave of the review round on the xchain-platform board. Every change was re-derived from the code rather than applied from the finding recommended option, and each carries a control that reproduces the original failure. Review findings: 6456 6514 6532 6544
… emits The double served a UTXO record the tracker never produces (a Number value with no sync sibling), so the encoder's real guards were exercised against a shape production cannot deliver. Review round 7 finding #6854. Also carries review round 6's encoder work.
Review-round fixes. Every payload-integrity guard sat behind the validate-all entry point, which only the JSON-RPC surface runs, while the public transaction builder forwarded straight through to the wire conversions unguarded. This file already re-applies four other guards for exactly that reason, so payload integrity was the oversight rather than the policy. Latin-1 validation now runs pre-compression and push-decodability post-compression, which is where each has to sit. The decodability guard sees Buffer inputs too: canonicalization is a property of the COMPILED push, so a one-byte Buffer in the minimal-op range loses everything the same way its string spelling does, and scoping it to strings left the hole open on precisely the direct-library surface the fix is about. Suite: 772 passing, 0 failing.
The test harness authored segwit inputs on every chain, including one whose consensus rules have no segwit. There the output is anyone-can-spend and a witnessUtxo input signs nothing the network enforces, so the harness was exercising a shape that cannot be valid and the encoder accepted it. Input selection now fails closed on a witness-program scriptPubKey when the network registry marks the chain as having no segwit, beside the existing taproot input guard and before any outpoint is reserved. The guard could not land without the harness first, which is why this is one change: with the fixtures unmigrated it reddens 95 tests across 8 files. The shared factory is now network-aware, so the fixture matches the chain. Suites pinned to a no-segwit chain only because it carried a convenient dust threshold move to a segwit-capable one; suites whose subject genuinely IS a chain without segwit keep their chain and take legacy inputs. Adds a control for the guard itself, and one test covering a raw-pubkey address branch the migration would otherwise have dropped.
…cannot pin the socket _post cleared its abort timer when the response HEADERS arrived and never released res.body, so a collector that answers 200 and then stalls held the socket open with nothing bounding it. Measured against a stalling collector, the socket was still open at three seconds and the batch was counted as shipped. That is worse than a leak, because the timeout was configured and did nothing: at a 400ms ship timeout the timer cleared at 22ms, so the stall outlived its only bound and the shipper reported success. The body is now cancelled inside the same then, within the abort timer's window, rather than after finally has cleared it. The stream is cancelled and never read, and a cancel on an already-errored body is swallowed. Every existing test injected a transport and bypassed the real fetch path, which is why this survived. The new case drives _post itself. Vendored copy, written by the hub sync script and never hand-edited. Parity is gated in the hub.
cors() was mounted below the API-key gate. A browser preflight is an OPTIONS carrying no x-api-key, because that header is not CORS-safelisted, which is exactly what forces the preflight in the first place. So on any deploy with a key configured the preflight was answered 401 with no Access-Control-Allow headers before cors() ran, and the browser never sent the real request. The gate's 401 and the limiter's 429s were also emitted bare, so a browser client saw an opaque network error rather than the shed status those gates exist to communicate. cors() now mounts above the gate, which is the order the hub already uses. With CORS disabled the middleware is a pure pass-through for every method, so the delta is bounded to keyed deploys that configure an origin. Control: 4 passing / 2 failing before, 6 passing / 0 failing after, and four of the six assertions pass identically both ways to prove auth is not weakened.
… bypassing createEnvelopeCancelTransaction is a second public transaction-producing path, exposed over JSON-RPC, and it built a spend of a caller-named commit outpoint without reading or writing the reservation map. It sits outside _buildTransaction so it never reached the duplicate-build guard either, and the comment there claimed every producing path passed through it. The race is real rather than theoretical: a create_tx whose caller-supplied set contains the commit output selected and spent that outpoint while an unsigned cancel of the same output was outstanding. Casing matters here too. This method accepted a mixed-case txid while create_tx lowercases its keys, so an uppercase txid produced a key that could never collide. The cancel now keys on the lowercased outpoint. A repeat of the same cancel still succeeds and returns byte-identical bytes, so the retry exemption is preserved; a foreign claim refuses with an operational error naming the outpoint. Control: 8 cases, 0 passing / 8 failing before, 8 passing / 0 failing after. The load-bearing one reproduces the race itself rather than asserting internal state.
…tore The guard's rationale named two in-process stores and recentBuilds is a third it did not count, so the comment understated what a second instance would split. Counting it in the rationale, with the store named alongside the other two.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Cuts xchain-encoder for the v0.15.0 release train. 16 commits from master.
Added
exactInputscreatetransaction option spends the caller's UTXO list verbatim./statuswithout silencing the 503.Fixed
Changed